﻿/**
 * @file slave_cmd.c
 * @brief this is a brief description
 * @details this is the detail description.
 * @author fulong 
 * @data 7/8/2014
 * @version 1.0
 * @par Copyright (c):
 * @par First build
 *     version: fulong 
 *     data: 7/8/2014
 */
#include "slave_cmd.h"
#include "../../action/action.h"
#include "common.h"
#include "../../../dev/uart.h"
#include "../../../hal/e2prom.h"

#ifdef MODBUS_ENABLE

#define read_param(iaddr,idata) idata = param[(iaddr)]
#define preset_single_reg_value(iaddr,idata) set_param(iaddr,idata)
#define read_holding_regs_value(iaddr,idata) read_param(iaddr,idata)

extern modbus_inner_var_struct modbus_inner_var[ ];
extern uint8 param[ PARAM_MAX ];

#define modbus_assert(condiction,ret) if(condiction){return (ret);}

#define READ_COIL_DATA_OUTPUT_ADDR_OFFSET 0
#define READ_COIL_DATA_OUTPTU_LEN_OFFSET 2
#define MAX_ADDR 0xFFFF
#define READ_MAX_LEN 0x7D0
#define READ_LEST_LEN 0x1
uint8 cmd_read_coil_status(const uint8 *data_buf, uint8 *rsp_buf) {
    uint16 addr, len;
    addr = data_buf[READ_COIL_DATA_OUTPUT_ADDR_OFFSET + 1] + (data_buf[READ_COIL_DATA_OUTPUT_ADDR_OFFSET] << 8);
    len = data_buf[READ_COIL_DATA_OUTPTU_LEN_OFFSET + 1] + (data_buf[READ_COIL_DATA_OUTPTU_LEN_OFFSET] << 8);
    /*先检查位地址是否正常*/
    modbus_assert(((len < READ_LEST_LEN) || (len > READ_MAX_LEN)), INVAILD_DATA);
    /*正常的话,才进行下面语句,因为一个字节为8位,可以保存8个连续地址信息*/
    len = len / 8 + 1;
    modbus_assert((addr > (MAX_ADDR - len)), INVAILD_ADDR);
    rsp_buf[0] = len;
    if (len == 1) {
        rsp_buf[1] = 0x03;
    }
    if (len == 2) {
        rsp_buf[1] = 0x03;
        rsp_buf[2] = 0x08;
    }
    return (MODBUS_NONE_EXCEPTION);
}
uint8 cmd_read_input_status(uint8 *data_buf, uint8 *rsp_buf) {
    uint16 addr, len, bit_sum, bit_len = 0;
    uint16 count, bit_counter = 0;
    uint8 addr_shift;
//  addr = data_buf[1] + ((uint16)data_buf[0] << 8);
    addr = data_buf[READ_COIL_DATA_OUTPUT_ADDR_OFFSET + 1];
    addr_shift = addr % 8;
    len = data_buf[READ_COIL_DATA_OUTPTU_LEN_OFFSET + 1] + ((uint16)data_buf[READ_COIL_DATA_OUTPTU_LEN_OFFSET] << 8);
    bit_sum = len;
    /*先检查位地址是否正常*/
    modbus_assert(((len < READ_LEST_LEN) || (len > READ_MAX_LEN)), INVAILD_DATA);
    /*正常的话,才进行下面语句,因为一个字节为8位,可以保存8个连续地址信息*/
    if (len != 0) {
        len--;
        len = len / 8 + 1;
    }
    modbus_assert((addr > (MAX_ADDR - len)), INVAILD_ADDR);
    rsp_buf[0] = len + 1;
    rsp_buf[1] = len;
    for (count = 0; count < (rsp_buf[1]); count++) {
        rsp_buf[2 + count] = 0;
        while (bit_len < 8 && bit_sum > 0) {
            if (modbus_inner_var[addr / 8 + bit_counter].M_byte & (0x1 << addr_shift)) {
                rsp_buf[2 + count] |= (1 << bit_len);
            }
            addr_shift++;
            if (addr_shift > 7) {
                addr_shift = 0;
                bit_counter++;
            }
            bit_len++;
            bit_sum--;
        }
        bit_len = 0;
    }
    return (MODBUS_NONE_EXCEPTION);
}
uint8 cmd_force_single_coil(uint8 *data_buf, uint8 *rsp_buf) {
    uint16 addr, operation;
    uint8 shift;
//  addr = data_buf[1] + ((uint16)data_buf[0] << 8);
    addr = data_buf[1];
    operation = data_buf[3] + ((uint16)data_buf[2] << 8);
    shift = addr % 8;
    switch (operation) {
        case 0:
            modbus_inner_var[addr / 8].M_byte = modbus_inner_var[addr / 8].M_byte & (~(0x1 << shift));
            break;
        case 0xFF00:
            modbus_inner_var[addr / 8].M_byte = modbus_inner_var[addr / 8].M_byte | (0x1 << shift);
            break;
        default:
            break;

    }
    rsp_buf[0] = 4;
    rsp_buf[2] = data_buf[1];
    rsp_buf[1] = data_buf[0];
    rsp_buf[4] = data_buf[3];
    rsp_buf[3] = data_buf[2];
    return (MODBUS_NONE_EXCEPTION);
}
uint8 cmd_read_holding_regs(uint8 *data_buf, uint8 *rsp_buf) {
    uint16 addr;
    uint16 data_len;
    uint16 i;
    data_len = ((uint16)data_buf[2] << 8) + data_buf[3];
    addr = data_buf[1];
    for (i = 0; i < data_len; i++) {
        read_holding_regs_value(i * 2 + 2 * addr, rsp_buf[2 + 2 * i]);
        read_holding_regs_value(i * 2 + 2 * addr + 1, rsp_buf[2 + 2 * i + 1]);
    }
    rsp_buf[0] = data_len * 2 + 1;
    rsp_buf[1] = data_len * 2;
    return (MODBUS_NONE_EXCEPTION);
}
uint8 cmd_read_input_regs(uint8 *data_buf, uint8 *rsp_buf) {
    return (MODBUS_NONE_EXCEPTION);
}
uint8 cmd_preset_single_reg(uint8 *data_buf, uint8 *rsp_buf) {
    uint16 addr;
    uint16 data;
    data = ((uint16)data_buf[2] << 8) + data_buf[3];
    addr = data_buf[1];
    preset_single_reg_value(addr, data);
    param[addr * 2] = (data >> 8);
    param[addr * 2 + 1] = data;
    rsp_buf[0] = 4;
    rsp_buf[1] = data_buf[0];
    rsp_buf[2] = data_buf[1];
    rsp_buf[3] = data_buf[2];
    rsp_buf[4] = data_buf[3];
    return (MODBUS_NONE_EXCEPTION);
}
uint8 cmd_force_multiple_regs(uint8 *data_buf, uint8 *rsp_buf) {
    uint16 addr;
    uint16 data;
    uint8 len, i;
    len = data_buf[4];
    addr = data_buf[1];
    for (i = 0; i < len; i += 2) {
        data = ((uint16)data_buf[5 + i] << 8) + data_buf[5 + i + 1];
        preset_single_reg_value(addr, data);
        param[addr * 2] = (data >> 8);
        param[addr * 2 + 1] = data;
        addr++;
    }
    rsp_buf[0] = 4;
    rsp_buf[1] = data_buf[0];
    rsp_buf[2] = data_buf[1];
    rsp_buf[3] = data_buf[2];
    rsp_buf[4] = data_buf[3];
}
#endif
